﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Timers;
using System.Net;
using HtmlAgilityPack;

///<summary>
///The AWLoadTesterLibrary provides simple C# methods for load testing websites.
///<para>
///Test runs can be specified along with their users, credentials, browsing pauses, simultaneous connections.  This library also
///helps collect and output the test run statistics in XML.
/// </para>
///</summary>
namespace AWLoadTesterLibrary
{
    /// <summary>
    /// Represents a complete run of the current tests.
    /// </summary>
    public class LoadTesterClass
    {
        /// <summary>
        /// The entire run shares a single Random number generator.
        /// </summary>
        Random currRandom = new Random();

        /// <summary>
        /// We keep this handy so we can tell if a test is still running
        /// </summary>
        System.Timers.Timer CurrentTimer;
        int TestTime = 0;
        int RunCount = 1;
        LoadTestRunResults CurrentResult;

        private LoadTestRunOptions CurrentOptions;

        /// <summary>
        /// Run the load test.
        /// </summary>
        /// <param name="opts">Holds all the options for this run</param>
        /// <param name="res">A "LoadTestRunResults" object that represents the results for all user tests in the session.</param>
        public void Run(LoadTestRunOptions opts, out LoadTestRunResults res)
        {
            CurrentResult = new LoadTestRunResults();
            res = CurrentResult;

            CurrentTimer  = new System.Timers.Timer();
            CurrentOptions = opts;

            if (Int32.TryParse(opts.TestTime, out TestTime) == false || TestTime<1)
            {
                return;
            }

            // Run the first test
            DoMinute(opts, res);

            if (TestTime > 1)
            {
                // Setup the timer for the other tests
                CurrentTimer = new System.Timers.Timer();
                CurrentTimer.Interval = 60000;
                CurrentTimer.AutoReset = true;
                CurrentTimer.Elapsed += new System.Timers.ElapsedEventHandler((e, x) =>
                {

                });
                CurrentTimer.Enabled = true;
            }

            return;
        }

        private void DoMinuteHandler(object o, ElapsedEventArgs e)
        {
            DoMinute(CurrentOptions, CurrentResult);
            if (++RunCount >= TestTime)
            {
                CurrentTimer.Stop();
            }
        }

        private void CleanUp()
        {
            ;
        }

        /// <summary>
        /// Find out if a test is running.  Checks that the minute timer is still going.
        /// </summary>
        /// <returns>True if this run is still activve, otherwise it returns False</returns>
        public bool HasActiveThreads()
        {
            bool res = false;

            if (CurrentTimer != null && CurrentTimer.Enabled)
            {
                return true;
            }

            if (CurrentOptions != null && CurrentOptions.ThreadList.Count > 0)
            {
                return true;
            }

            return res;
        }

        /// <summary>
        /// Executed every minute.  Start's all the users' browse actions.  
        /// <para>Spawns one browse thread per user, pausing a seconds before starting each user.</para>
        /// </summary>
        private void DoMinute(LoadTestRunOptions opts, LoadTestRunResults res)
        {
            int userCount = 0;
            int userConns = 0;
            int userBrowseTime = 0;

            if (Int32.TryParse(opts.UsersMin, out userCount) == false)
            {
                return;
            }

            if (Int32.TryParse(opts.ConConnections, out userConns) == false)
            {
                return;
            }

            if (Int32.TryParse(opts.BrowseTime, out userBrowseTime) == false)
            {
                return;
            }

            for (int i = 0; i < userCount; i++)
            {
                // Spawn a thread for a user then sleep 2 seconds.
                LoadTestUser currUser = new LoadTestUser();
                currUser.Util.RandomSleepMax = userBrowseTime;
                currUser.Util.CurrentRandom = currRandom;

                Thread userBrowseThread = new Thread(new ThreadStart(() =>
                {
                    LoadTestUserResult currRes = currUser.Browse(opts, userConns, userBrowseTime);
                    res.UserResults.Add(currRes);
                }));
                userBrowseThread.Name = "AWLoadTesterTestThread";
                userBrowseThread.Start();
                opts.ThreadList.Add(userBrowseThread);

               // Thread.Sleep(1000);
            }
        }
    }

    /// <summary>
    /// Represents the results of an entire load test run.
    /// </summary>
    public class LoadTestRunResults
    {
        /// <summary>
        /// List of results from each user in the test
        /// </summary>
        public List<LoadTestUserResult> UserResults { get; set; }

        /// <summary>
        /// Specifies whether the results are completed or not
        /// </summary>
        public bool Completed { get; set; }

        /// <summary>
        /// Creates a new load test run.
        /// </summary>
        public LoadTestRunResults()
        {
            UserResults = new List<LoadTestUserResult>();
            Completed = false;
        }
    }
}
